<?php

namespace App\Http\Controllers\Api;

use GuzzleHttp\Exception\RequestException;
use function GuzzleHttp\Psr7\str;
use Illuminate\Http\Request;
use App\Http\Controllers\ApiController;
use App\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\UnauthorizedException;
use Validator;
use GuzzleHttp\Client;

class UserController extends ApiController
{

    /**
     * 登陆
     *
     * @return \Illuminate\Http\Response
     */
    public function login(Request $request)
    {
        $mobile = $request->input('mobile');
        $password = $request->input('password');
        $user = User::Where('mobile', $mobile)->first();

        if (!$user) {
            return $this->failed("用户名或密码错误");
        }

        if ($user->status == 0) {
            return $this->failed("账号已被禁用");
        }

        $client = new Client();
        try {
            $url = request()->root() . '/api/oauth/token';

            $params = array_merge(config('passport.proxy'), [
                'username' => $mobile,
                'password' => $password,
            ]);

            $respond = $client->request('POST', $url, ['form_params' => $params]);

        } catch (RequestException $e) {
            return $this->failed("账号验证失败");

        }
        if ($respond->getStatusCode() == 401) {
            return $this->failed("账号验证失败");

        }
        $data["user"] = array("is_evaluate" => $user->is_evaluate);
        $token = json_decode($respond->getBody()->getContents(), true);
        $data['token'] =  $token['access_token'];
        return $this->success($data);

//        if(Auth::attempt(['mobile' => request('mobile'), 'password' => request('password'), 'status' => 1])){
//            $user = Auth::user();
////            $wx_openid = DB::table('user_extra')->where(['user_id' => $user->id])->value('wx_openid');
//            $data["user"] = array("is_evaluate" => $user->is_evaluate);
//            $data['token'] =  $user->createToken('xiaoli_health')->accessToken;
////            $data['wx_openid'] = empty($wx_openid) ? false : true;
//            return $this->success($data);
//        }
//        else{
//           return $this->failed("用户名或密码不正确");
        }


    /**
     * 注册
     *
     * @return \Illuminate\Http\Response
     */
    public function register(Request $request)
    {

        $mobile = $request->input("mobile", "");
        $verify_code = $request->input("verify_code", "");
        $password = $request->input("password", "");
        $invite_code = $request->input("invite_code", "");

        //验证用户输入
        if (empty($mobile)) {
            return $this->failed("手机号不能为空");
        }
        if (empty($verify_code)) {
            return $this->failed("验证码不能为空");
        }
        if (empty($password)) {
            return $this->failed("密码不能为空");
        }
//        if (empty($invite_code)) {
//            return $this->failed("邀请码不能为空");
//        }
        if(!preg_match("/^1[3456789]\d{9}$/", $mobile)) {
            return $this->failed("手机号格式不正确");
        }

        $type = 1; //注册
        $send_code_key = "user_send_code_{$type}_{$mobile}";

        if($verify_code != Cache::get($send_code_key)) {
            return $this->failed("验证码不正确");
        }

        if(!preg_match("/^\w{6,18}$/", $password)) {
            return $this->failed("密码只能包含字母，数字和下划线，长度为6至18位");
        }

        //验证手机号是否存在
        $user_is_exist = DB::table('user')->where(array('mobile' => $mobile, 'status' => 1))->first();
        if (!empty($user_is_exist)) {
            return $this->failed("该手机号已注册");
        }

        //邀请码是否存在 && 未被使用
//        $code_is_exist = DB::table('invitation_code')->where(array("code" => $invite_code, "is_delete" => 0))->first();
//        if (empty($code_is_exist)) {
//            return $this->failed("邀请码不存在");
//        }
//        if ($code_is_exist->expire_time < time()) {
//            return $this->failed("邀请码已失效");
//        }

        //验证通过后注册 && 邀请码设为已用 && 创建健康报告
        DB::beginTransaction(); //开启事务
//        $user_id = DB::table('user')->insertGetId(array('mobile' => $mobile, 'password' => bcrypt($password), 'code_id' => $code_is_exist->id));
        $user_id = DB::table('user')->insertGetId(array('mobile' => $mobile, 'password' => bcrypt($password)));
        $report_res = DB::table('user_health_report')->insert(['user_id' => $user_id]);
        if (empty($user_id) || empty($report_res)) {
            DB::rollBack(); //回滚事务
            return $this->failed("注册失败");
        }
        Cache::forget($send_code_key);
        DB::commit(); //提交事务
        return $this->login($request);
    }


    /**
     * 发送验证码
     *
     * @param Request $request
     */
    public function sendCode(Request $request)
    {
        $mobile = $request->input("mobile", 0);
        $type = $request->input("type", 0); //验证码来源类型，1用户注册 2用户忘记密码 3核销端忘记密码

        //验证用户输入
        if (empty($mobile)) {
           return $this->failed("手机号不能为空");
        }
        if (empty($type)) {
            return  $this->failed("参数错误");
        }
        if (!in_array($type, array(1, 2, 3))) { //验证码来源类型，1用户注册 2用户忘记密码 3核销端忘记密码
            return $this->failed("参数错误");
        }
        if(!preg_match("/^1[3456789]\d{9}$/", $mobile)) {
            return $this->failed("手机号格式不正确");
        }

        //验证用户发送验证码是否达到上限
        $user_ip = $request->getClientIp();

        $send_count_key = "user_send_count_{$type}_{$user_ip}";
        $send_code_key = "user_send_code_{$type}_{$mobile}";
        $send_code_is_expire_key = "user_send_code_is_expire_{$type}_{$mobile}";
        if (Cache::has($send_code_is_expire_key)) {
            return $this->failed("验证码发送频繁");
        }
        if (Cache::has($send_count_key)) {

            $send_count = Cache::get($send_count_key);
            if ($send_count > 50) {
                return $this->failed("验证码发送频繁");
            } else {
                Cache::increment($send_count_key);
            }
        } else {
            Cache::add($send_count_key, 1, 60 * 1); //暂定同一个ip 10小时内只能发送5次验证码
        }
        $res = send_msg_code($mobile);
        Cache::put($send_code_is_expire_key, 1, 1); //发送成功设置一分钟后再次发送限制
        if (empty($res['flag'])) {
            return $this->failed("发送失败");
        }
        Cache::put($send_code_key, $res['data'], 10); //保存验证码10分钟
        return $this->success("发送成功");
    }

    /**
     * 找回密码
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function findPassword(Request $request)
    {
        $mobile = $request->input("mobile", "");
        $verify_code = $request->input("verify_code", "");
        $password = $request->input("password", "");

        //验证用户输入
        if (empty($mobile)) {
            return $this->failed("手机号不能为空");
        }
        if (empty($verify_code)) {
            return $this->failed("验证码不能为空");
        }
        if (empty($password)) {
            return $this->failed("新密码不能为空");
        }

        if(!preg_match("/^1[3456789]\d{9}$/", $mobile)) {
            return $this->failed("手机号格式不正确");
        }

        //查找手机号是否已注册
        $user_is_exist = DB::table('user')->where('mobile', $mobile)->first();
        if (empty($user_is_exist)) {
            return $this->failed("该用户未注册");
        }

        $type = 2; //忘记密码
        $send_code_key = "user_send_code_{$type}_{$mobile}";

        if($verify_code != Cache::get($send_code_key)) {
            return $this->failed("验证码不正确");
        }

        if(!preg_match("/^\w{6,18}$/", $password)) {
            return $this->failed("密码只能包含字母，数字和下划线，长度为6至18位");
        }


        //验证通过后修改密码
        $user_res = DB::table('user')->where('id', $user_is_exist->id)->update(array('password' => bcrypt($password)));
        if ($user_res === false) {
            return $this->failed("找回密码失败");
        }
        Cache::forget($send_code_key);
        return $this->success("找回密码成功");
    }


    /**
     * 评测
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function evaluate(Request $request)
    {
        $user = Auth::user();
        $user_id = $user->id;
        $sex = $request->input("sex", 0);
        $birthday = $request->input("birthday", "");
        $height = $request->input("height", "");
        $weight = $request->input("weight", "");
        $sport_type = $request->input("sport_type", ""); // 1极轻体力劳动 2轻体力劳动 3中等体力劳动 4重体力劳动

        if (empty($sex)) {
            return $this->failed("性别不能为空");
        }
        if (empty($birthday)) {
            return $this->failed("生日不能为空");
        }
        if (empty($height)) {
            return $this->failed("身高不能为空");
        }
        if (empty($weight)) {
            return $this->failed("体重不能为空");
        }
        if (empty($sport_type)) {
            return $this->failed("运动等级不能为空");
        }

        if (!in_array($sex, array(1, 2))) {
            return $this->failed("性别选择不正确");
        }
        if (!valid_date($birthday)) {
            return $this->failed("生日日期格式不正确");
        }
        if (time() < strtotime($birthday)) {
            return $this->failed("生日日期不正确");
        }
        if (!in_array($sport_type, array(1, 2, 3, 4))) {
            return $this->failed("运动等级选择不正确");
        }

        //验证成功后生成数据
        $bmi = round($weight / (($height / 100) * ($height / 100)), 1); //BMI
        $sex_value = $sex == 1 ? 1 : 0;
        $age = date("Y") - date("Y", strtotime($birthday));
        $bf = round(1.2 * $bmi + 0.23 * $age - 5.4 -10.8 * $sex_value, 1); //1瘦 2偏瘦 3标准 4微胖 5肥胖
        $standard_weight = $height - 105; //标准身高

        if ($bmi < 18.5) {
            $bmi_type = 1;
            switch ($sport_type) {
                case 1:
                    $caloric = 35 * $standard_weight;
                    $min_caloric = 33 * $standard_weight;
                    $max_caloric = 37 * $standard_weight;
                    break;
                case 2:
                    $caloric = 40 * $standard_weight;
                    $min_caloric = 38 * $standard_weight;
                    $max_caloric = 42 * $standard_weight;
                    break;
                case 3:
                    $caloric = 45 * $standard_weight;
                    $min_caloric = 43 * $standard_weight;
                    $max_caloric = 47 * $standard_weight;
                    break;
                case 4:
                    $caloric = 50 * $standard_weight;
                    $min_caloric = 45 * $standard_weight;
                    $max_caloric = 55 * $standard_weight;
                    break;
                default:
                    break;

            }
        } elseif ($bmi >= 18.5 && $bmi < 24) {
            $bmi_type = 2;
            switch ($sport_type) {
                case 1:
                    $caloric = 27 * $standard_weight;
                    $min_caloric = 25 * $standard_weight;
                    $max_caloric = 30 * $standard_weight;
                    break;
                case 2:
                    $caloric = 35 * $standard_weight;
                    $min_caloric = 33 * $standard_weight;
                    $max_caloric = 37 * $standard_weight;
                    break;
                case 3:
                    $caloric = 40 * $standard_weight;
                    $min_caloric = 38 * $standard_weight;
                    $max_caloric = 42 * $standard_weight;
                    break;
                case 4:
                    $caloric = 45 * $standard_weight;
                    $min_caloric = 43 * $standard_weight;
                    $max_caloric = 47 * $standard_weight;
                    break;
                default:
                    break;

            }
        } elseif ($bmi >= 24 && $bmi < 28) {
            $bmi_type = 3;
            switch ($sport_type) {
                case 1:
                    $caloric = 22 * $standard_weight;
                    $min_caloric = 20 * $standard_weight;
                    $max_caloric = 25 * $standard_weight;
                    break;
                case 2:
                    $caloric = 30 * $standard_weight;
                    $min_caloric = 28 * $standard_weight;
                    $max_caloric = 32 * $standard_weight;
                    break;
                case 3:
                    $caloric = 35 * $standard_weight;
                    $min_caloric = 33 * $standard_weight;
                    $max_caloric = 37 * $standard_weight;
                    break;
                case 4:
                    $caloric = 40 * $standard_weight;
                    $min_caloric = 38 * $standard_weight;
                    $max_caloric = 42 * $standard_weight;
                    break;
                default:
                    break;

            }
        } else {
            $bmi_type = 4;
            switch ($sport_type) {
                case 1:
                    $caloric = 17 * $standard_weight;
                    $min_caloric = 15 * $standard_weight;
                    $max_caloric = 20 * $standard_weight;
                    break;
                case 2:
                    $caloric = 22 * $standard_weight;
                    $min_caloric = 20 * $standard_weight;
                    $max_caloric = 25 * $standard_weight;
                    break;
                case 3:
                    $caloric = 30 * $standard_weight;
                    $min_caloric = 28 * $standard_weight;
                    $max_caloric = 32 * $standard_weight;
                    break;
                case 4:
                    $caloric = 35 * $standard_weight;
                    $min_caloric = 33 * $standard_weight;
                    $max_caloric = 42 * $standard_weight;
                    break;
                default:
                    break;

            }
        }

        //根据性别，体脂率判断体型
        if ($sex == 1) {
            if ($bf < 11) {
                $bf_type = 1;
            } elseif ($bf >= 11 && $bf < 16) {
                $bf_type = 2;
            } elseif ($bf >= 16 && $bf < 21) {
                $bf_type = 3;
            } elseif ($bf >=21 && $bf < 26) {
                $bf_type = 4;
            } else {
                $bf_type = 5;
            }
        } else {
            if ($bf < 21) {
                $bf_type = 1;
            } elseif ($bf >= 21 && $bf < 26) {
                $bf_type = 2;
            } elseif ($bf >= 26 && $bf < 31) {
                $bf_type = 3;
            } elseif ($bf >=31 && $bf < 36) {
                $bf_type = 4;
            } else {
                $bf_type = 5;
            }
        }

        //判断总体型
        if ($bf_type < 3) {
            $body_type = 1;
        } elseif ($bf_type == 3) {
            if ($bmi_type < 2) {
                $body_type = 1;
            } elseif ($bmi_type ==2) {
                $body_type = 2;
            } else {
                $body_type = 3;
            }
        } else {
            $body_type = 3;
        }

        //计算健康体重
        $min_weight = round(18.5 * $height * $height / 100 / 100, 1);
        $max_weight = round(24 * $height * $height / 100 / 100, 1);

        DB::beginTransaction(); //开启事务
        $user_res = DB::table('user')->where('id', $user->id)->update(array("sex" => $sex, "birthday" => $birthday, "height" => $height, "weight" => $weight, "sport_type" => $sport_type, "is_evaluate" => 1));

        $report_res = DB::table('user_health_report')->where('user_id', $user_id)->update([
            'bmi' => $bmi,
            'bmi_type' => $bmi_type,
            'bf' => $bf,
            'bf_type' => $bf_type,
            'body_type' => $body_type,
            'min_weight' => $min_weight,
            'max_weight' => $max_weight,
            'caloric' => $caloric,
            'min_caloric' => $min_caloric,
            'max_caloric' => $max_caloric
        ]);

        //修改今日健康日记热量
        $date = date("Ymd");
        $health_diary = DB::table('user_health_diary')->where([['user_id', '=', $user_id], ['date', '=', $date]])->first();
        $health_res = true;
        if(!empty($health_diary)) {
            $health_res = DB::table('user_health_diary')->where('id', $health_diary->id)->update(['all_caloric' => $caloric]);
        }

        if ($user_res === false || $report_res === false || $health_res === false) {
            DB::rollBack(); //回滚事务
            return $this->failed("评测失败");
        }
        DB::commit(); //提交事务
        return $this->success("评测成功");

    }

    /**
     * 修改密码
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function modifyPassword(Request $request)
    {
        $user = Auth::user();
        $old_password = $request->input("old_password", "");
        $new_password = $request->input("new_password", "");
        if (!\Hash::check($old_password, $user->password)) { //原始密码和数据库里的密码进行比对
            return $this->failed("原密码不正确");
        }
        if(!preg_match("/^\w{6,18}$/", $new_password)) {
            return $this->failed("新密码只能包含字母，数字和下划线，长度为6至18位");
        }
        $res = DB::table('user')->where('id', $user->id)->update(array('password' => bcrypt($new_password)));
        if ($res === false) {
            return $this->failed("修改密码失败");
        }
        return $this->success("修改密码成功");
    }

    /**
     * 获取评测填写的信息
     *
     * @return \Illuminate\Http\Response
     */
    public function getUserInfo()
    {
        $user = Auth::user();
        if (empty($user->status)) {
            return $this->failed("用户不存在");
        }
        $data["user"] = array(
            "mobile" => $user->mobile,
            "sex" => $user->sex,
            "birthday" => $user->birthday,
            "height" => $user->height,
            "weight" => $user->weight,
            "sport_type" => $user->sport_type
        );
        return $this->success($data);
    }

    /**
     * 健康报告
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function healthReport()
    {
        $user = Auth::user();
        $report = DB::table('user_health_report')->where(['user_id' => $user->id])->first();
        $report->min_bmi = 18.5;
        $report->max_bmi = 23.9;
        if ($user->sex == 1) {
            $report->min_bf = 16;
            $report->max_bf = 20.9;
        } else {
            $report->min_bf = 26;
            $report->max_bf = 30.9;
        }

        unset($report->user_id);
        return $this->success(['report' => $report]);
    }


    /**
     * 退出登录
     */
    public function logout()
    {
        if (Auth::guard('api')->check()) {
            Auth::guard('api')->user()->token()->delete();
        }

        return $this->success("退出成功");
    }

    /**
     * 获取用户openid
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
//    public function getUserWxOpenId(Request $request)
//    {
//        $code = $request->input("code");
//        $wechat_config = config('pay.wechat');
//        $url = "https://api.weixin.qq.com/sns/jscode2session?appid={$wechat_config['mini_appid']}&secret={$wechat_config['miniapp_secret']}&js_code={$code}&grant_type=authorization_code";
//        $client = new Client();
//        $req = $client->get($url);
//        $res =  $req->getBody();
//        if (empty($res['openid'])) {
//            return $this->failed("获取失败");
//        }
//        DB::table('user_extra')->insert(['wx_openid' => $res['openid'], 'wx_unionid' => (empty($res['unionid']) ? '' : $res['unionid'])]);
//        return $this->success("获取成功");
//    }
}
